package dnl.jexem.prcs;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.hyperic.sigar.ProcCpu;
import org.hyperic.sigar.ProcCredName;
import org.hyperic.sigar.ProcExe;
import org.hyperic.sigar.ProcMem;
import org.hyperic.sigar.ProcTime;
import org.hyperic.sigar.Sigar;
import org.hyperic.sigar.SigarException;

/**
 * 
 * @author Daniel Orr
 * 
 */
public class SigarProcessOperations implements ProcessOperations {

	private static boolean DEBUG = false;

	private Sigar sigar = new Sigar();

	@Override
	public ProcessInfo getProcess(int pid) {
		ProcessInfo processInfo = new ProcessInfo();
		processInfo.setProcessID(pid);
		try {
			ProcMem procMem = sigar.getProcMem(pid);
			processInfo.setMemUsage(procMem.getSize());
		} catch (SigarException e) {
			err(e, pid);
		}
		try {
			ProcCpu procCpu = sigar.getProcCpu(pid);
			processInfo.setCpuUsagePercent(procCpu.getPercent());
		} catch (SigarException e) {
			err(e, pid);
		}
		try {
			ProcCredName procCredName = sigar.getProcCredName(pid);
			processInfo.setUserID(procCredName.getUser());
		} catch (SigarException e) {
			err(e, pid);
		}
		try {
			ProcTime procTime = sigar.getProcTime(pid);
			processInfo.setStartTime(procTime.getStartTime() + "");
		} catch (SigarException e) {
			err(e, pid);
		}
		boolean procExeFailed = false;
		try {
			ProcExe procExe = sigar.getProcExe(pid);
			processInfo.setCmd(procExe.getName());
		} catch (SigarException e) {
			procExeFailed = true;
			err(e, pid);
		}
		try {
			String[] procArgs = sigar.getProcArgs(pid);
			if (procExeFailed && procArgs.length > 0) {
				processInfo.setCmd(procArgs[0]);
			}
			Object[] sub = ArrayUtils.subarray(procArgs, 1, procArgs.length);
			processInfo.setArguments(StringUtils.join(sub, " "));
		} catch (SigarException e) {
			err(e, pid);
		}
		return processInfo;
	}

	private static void err(Exception e, int pid) {
		if (!DEBUG)
			return;
		System.err.println(e.getMessage() + " - pid=" + pid);
	}

	@Override
	public List<ProcessInfo> getProcesses() {
		try {
			long[] procList = sigar.getProcList();
			List<ProcessInfo> result = new ArrayList<ProcessInfo>();
			for (long pid : procList) {
				result.add(getProcess((int) pid));
			}
			return result;
		} catch (SigarException e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public List<ProcessInfo> grepProcesses(String grepExpression) {
		List<ProcessInfo> processes = getProcesses();
		List<ProcessInfo> result = new ArrayList<ProcessInfo>();

		for (ProcessInfo processInfo : processes) {
			String stringNixStyle = processInfo.toStringNixStyle();
			if(stringNixStyle.indexOf(grepExpression) >= 0){
				result.add(processInfo);
			}
		}
		return result;
	}

	@Override
	public boolean killProcess(int pid) {
		try {
			sigar.kill(pid, 1);
		} catch (SigarException e) {
			e.printStackTrace();
		}
		return true;
	}

}
